<?php

namespace Gql\ScalarType;

use Gql\Contracts\TypeAbstract;
use GraphQL\Language\AST\BooleanValueNode;
use GraphQL\Language\AST\FloatValueNode;
use GraphQL\Language\AST\IntValueNode;
use GraphQL\Language\AST\StringValueNode;
use phpDocumentor\Reflection\Types\Boolean;

class MixedType extends TypeAbstract
{

    /** @var string */
    public $description =
        'Int | Float | String | Boolean';


    /**
     * @param mixed $value
     *
     * @return float|null
     *
     * @throws Error
     */
    public function serialize($value)
    {
        return $this->coerceFloat($value);
    }

    private function coerceFloat($value)
    {

        if (!is_numeric($value) && $value !== true && $value !== false && !is_string($value)) {
            throw new Error(
                'Invalid value: ' .
                Utils::printSafe($value)
            );
        }

        return (float)$value;
    }

    /**
     * @param mixed $value
     * @return float|null
     * @throws Error
     */
    public function parseValue($value)
    {
        return $this->coerceFloat($value);
    }

    /**
     * @param Node $valueNode
     * @param mixed[]|null $variables
     * @return float|null
     * @throws \Exception
     */
    public function parseLiteral($valueNode, ?array $variables = null)
    {

        if (
            is_bool($valueNode)
            || is_numeric($valueNode)
            || is_string($valueNode)
        ) {
            return $valueNode;
        }
        if (
            $valueNode instanceof StringValueNode
            || $valueNode instanceof IntValueNode
            || $valueNode instanceof BooleanValueNode
        ) {
            return $valueNode->value;
        }
        // Intentionally without message, as all information already in wrapped Exception
        throw new \Exception();
    }


}